package com.hqd.ch03.v48.factory.config;

import com.hqd.ch03.utils.ObjectUtils;
import com.hqd.ch03.v48.beans.BeanMetadataElement;
import com.hqd.ch03.v48.beans.factory.config.BeanDefinition;
import com.hqd.ch03.v48.config.ConstructorArgumentValues;
import com.hqd.ch03.v48.config.MutablePropertyValues;
import com.hqd.ch03.v48.factory.support.GenericBeanDefinition;
import com.hqd.ch03.v48.utils.BeanFactoryUtils;
import com.hqd.ch03.v48.utils.StringUtils;

public class BeanDefinitionHolder implements BeanMetadataElement {

    private String[] aliases;
    private BeanDefinition beanDefinition;
    private String beanName;


    public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
        this(beanDefinition, beanName, null);
    }

    public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, String[] aliases) {
        this.beanDefinition = beanDefinition;
        this.beanDefinition.setId(beanName);
        this.beanName = beanName;
        this.aliases = aliases;
    }

    public BeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
        this.beanDefinition = beanDefinitionHolder.getBeanDefinition();
        this.beanName = beanDefinitionHolder.getBeanName();
        this.aliases = beanDefinitionHolder.getAliases();
    }

    public BeanDefinitionHolder() {
        this.beanDefinition = new GenericBeanDefinition();
    }

    public BeanDefinition getBeanDefinition() {
        return this.beanDefinition;
    }

    public String getBeanName() {
        return this.beanName;
    }


    public String[] getAliases() {
        return this.aliases;
    }

    @Override
    public Object getSource() {
        return this.beanDefinition.getSource();
    }

    public boolean matchesName(String candidateName) {
        return (candidateName != null && (candidateName.equals(this.beanName) ||
                candidateName.equals(BeanFactoryUtils.transformedBeanName(this.beanName)) ||
                ObjectUtils.containsElement(this.aliases, candidateName)));
    }

    public String getShortDescription() {
        if (this.aliases == null) {
            return "Bean definition with name '" + this.beanName + "'";
        }
        return "Bean definition with name '" + this.beanName + "' and aliases [" + StringUtils.arrayToCommaDelimitedString(this.aliases) + ']';
    }

    public String getLongDescription() {
        return getShortDescription() + ": " + this.beanDefinition;
    }

    @Override
    public String toString() {
        return getLongDescription();
    }


    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof BeanDefinitionHolder)) {
            return false;
        }
        BeanDefinitionHolder otherHolder = (BeanDefinitionHolder) other;
        return this.beanDefinition.equals(otherHolder.beanDefinition) &&
                this.beanName.equals(otherHolder.beanName) &&
                ObjectUtils.nullSafeEquals(this.aliases, otherHolder.aliases);
    }

    @Override
    public int hashCode() {
        int hashCode = this.beanDefinition.hashCode();
        hashCode = 29 * hashCode + this.beanName.hashCode();
        hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.aliases);
        return hashCode;
    }

    public String getId() {
        return this.beanName;
    }

    public void setId(String beanName) {
        this.beanName = beanName;
        this.beanDefinition.setId(beanName);
    }

    public void setLazyInit(boolean lazyInit) {
        this.beanDefinition.setLazyInit(lazyInit);
    }

    public void setBeanClass(String beanClassName) {
        this.beanDefinition.setBeanClassName(beanClassName);
    }

    public void setInitMethodName(String initMethodName) {
        this.beanDefinition.setInitMethodName(initMethodName);
    }

    public void setDestroyMethodName(String destroyMethodName) {
        this.beanDefinition.setDestroyMethodName(destroyMethodName);
    }

    public void setProperties(MutablePropertyValues pvs) {
        this.beanDefinition.setProperties(pvs);
    }

    public void setConstructorArgumentValues(ConstructorArgumentValues cvs) {
        this.beanDefinition.setConstructorArgumentValues(cvs);
    }

    public String getBeanClassName() {
        return this.beanDefinition.getBeanClassName();
    }

    public CharSequence getScope() {
        return this.beanDefinition.getScope();
    }

    public void setScope(String scope) {
        this.beanDefinition.setScope(scope);
    }

    public void setDescription(String description) {
        this.beanDefinition.setDescription(description);
    }
}
